#include "D3D11.h"
#include "D3D11Shader.h"
#include "D3Dcompiler.h"
#include <string>
#include "tinyxml2\tinyxml2.h"


void main()
{
	// This flag adds support for surfaces with a different color channel 
	// ordering than the API default. It is required for compatibility with
	// Direct2D.
	UINT creationFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;

	#if defined(_DEBUG)
	// If the project is in a debug build, enable debugging via SDK Layers.
	creationFlags |= D3D11_CREATE_DEVICE_DEBUG;
	#endif

	// This example only uses feature level 9.1.
	D3D_FEATURE_LEVEL featureLevels[] = 
	{
		D3D_FEATURE_LEVEL_11_0
	};

	// Create the Direct3D 11 API device object and a corresponding context.
	ID3D11Device* device;
	ID3D11DeviceContext* context;
	HRESULT result = D3D11CreateDevice(
		nullptr, // Specify nullptr to use the default adapter.
		D3D_DRIVER_TYPE_HARDWARE,
		nullptr,
		creationFlags,
		featureLevels,
		ARRAYSIZE(featureLevels),
		D3D11_SDK_VERSION, // Windows Store apps must set this to D3D11_SDK_VERSION.
		&device, // Returns the Direct3D device created.
		nullptr,
		&context // Returns the device immediate context.
		);

	if(result != S_OK)
	{
		return;
	}
	std::string directory = "F:\\GoogleProject\\WP8Core\\RTE\\Debug\\RTEComponent\\";
	std::string directoryOutput = "F:\\GoogleProject\\WP8Core\\RTE\\RTE\\RTE\\Assets\\ShaderDesc\\";
	std::string searchPath = directory;
	searchPath.append("*.cso");

	HANDLE hFind = INVALID_HANDLE_VALUE;
	WIN32_FIND_DATAA ffd;
	LARGE_INTEGER filesize;
	hFind = FindFirstFileA(searchPath.c_str(), &ffd);
	if (INVALID_HANDLE_VALUE == hFind) 
	{
		device->Release();
		return;
	} 
   
	// List all the files in the directory with some info about them.

	do
	{
		if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
		{

		}
		else
		{
			filesize.LowPart = ffd.nFileSizeLow;
			filesize.HighPart = ffd.nFileSizeHigh;

			if(strstr(ffd.cFileName, "_PS.cso") != NULL || strstr(ffd.cFileName, "_VS.cso") != NULL)
			{
				std::string filePath = directory;
				filePath.append(ffd.cFileName);
				std::string outputPath = directoryOutput;
				outputPath.append(ffd.cFileName, strlen(ffd.cFileName) - 3);
				outputPath.append("desc");
				FILE* f = fopen(filePath.c_str(), "rb");
				if(f == NULL) continue;
				fseek(f, 0, SEEK_END);
				long size = ftell(f);
				fseek(f, 0, SEEK_SET);
				char* buffer = new char[size];
				fread(buffer, 1, size, f);
				fclose(f);
				
				ID3D11ShaderReflection* pReflector = NULL; 
				result =  D3DReflect( buffer, size, IID_ID3D11ShaderReflection, (void**) &pReflector );
				if(S_OK == result)
				{
					tinyxml2::XMLDocument doc;
					D3D11_SHADER_DESC shaderDesc;
					result = pReflector->GetDesc(&shaderDesc);
					if(S_OK == result)
					{
						tinyxml2::XMLElement *inputListNode = doc.NewElement("inputList");
						inputListNode->SetAttribute("count", shaderDesc.InputParameters);
						doc.InsertEndChild(inputListNode);
						for(int i = 0;i < shaderDesc.InputParameters;i++)
						{
							D3D11_SIGNATURE_PARAMETER_DESC inputDesc;
							result = pReflector->GetInputParameterDesc(i, &inputDesc);
							char writeText[32];
							sprintf(writeText, "%d\n%s\n", i, inputDesc.SemanticName);
							fwrite(writeText, 1, strlen(writeText), f);
							tinyxml2::XMLElement *inputNode = doc.NewElement("input");
							inputNode->SetAttribute("index", i);
							inputNode->SetAttribute("semantic", inputDesc.SemanticName);
							int inputFormat = DXGI_FORMAT_UNKNOWN;
							switch(inputDesc.ComponentType)
							{
							case D3D_REGISTER_COMPONENT_UINT32:
								if(inputDesc.Mask == 0x1)
								{
									inputFormat = DXGI_FORMAT_R32_UINT;
								}
								else if(inputDesc.Mask == 0x3)
								{
									inputFormat = DXGI_FORMAT_R32G32_UINT;
								}
								else if(inputDesc.Mask == 0x7)
								{
									inputFormat = DXGI_FORMAT_R32G32B32_UINT;
								}
								else if(inputDesc.Mask == 0xF)
								{
									inputFormat = DXGI_FORMAT_R32G32B32A32_UINT;
								}
								break;
							case D3D_REGISTER_COMPONENT_SINT32:
								if(inputDesc.Mask == 0x1)
								{
									inputFormat = DXGI_FORMAT_R32_SINT;
								}
								else if(inputDesc.Mask == 0x3)
								{
									inputFormat = DXGI_FORMAT_R32G32_SINT;
								}
								else if(inputDesc.Mask == 0x7)
								{
									inputFormat = DXGI_FORMAT_R32G32B32_SINT;
								}
								else if(inputDesc.Mask == 0xF)
								{
									inputFormat = DXGI_FORMAT_R32G32B32A32_SINT;
								}
								break;
							case D3D_REGISTER_COMPONENT_FLOAT32:
								if(inputDesc.Mask == 0x1)
								{
									inputFormat = DXGI_FORMAT_R32_FLOAT;
								}
								else if(inputDesc.Mask == 0x3)
								{
									inputFormat = DXGI_FORMAT_R32G32_FLOAT;
								}
								else if(inputDesc.Mask == 0x7)
								{
									inputFormat = DXGI_FORMAT_R32G32B32_FLOAT;
								}
								else if(inputDesc.Mask == 0xF)
								{
									inputFormat = DXGI_FORMAT_R32G32B32A32_FLOAT;
								}
								break;
							case D3D_REGISTER_COMPONENT_UNKNOWN:
							default:
								break;
							}
							inputNode->SetAttribute("dxgi_format", inputFormat);
							inputListNode->InsertEndChild(inputNode);
						}
						tinyxml2::XMLElement *resourceListNode = doc.NewElement("resourceList");
						resourceListNode->SetAttribute("count", shaderDesc.BoundResources);
						doc.InsertEndChild(resourceListNode);
						for(int i = 0; i < shaderDesc.BoundResources; i++)
						{
							D3D11_SHADER_INPUT_BIND_DESC resourceDesc;
							result = pReflector->GetResourceBindingDesc(i, &resourceDesc);
							tinyxml2::XMLElement *resourceNode = doc.NewElement("resource");
							resourceNode->SetAttribute("index", i);
							resourceNode->SetAttribute("name", resourceDesc.Name);
							resourceNode->SetAttribute("D3D_SHADER_INPUT_TYPE", resourceDesc.Type);
							resourceNode->SetAttribute("bindpoint", resourceDesc.BindPoint);
							resourceNode->SetAttribute("bindcount", resourceDesc.BindCount);
							resourceListNode->InsertEndChild(resourceNode);
						}
						tinyxml2::XMLElement *constantBufferListNode = doc.NewElement("constantBufferList");
						constantBufferListNode->SetAttribute("count", shaderDesc.ConstantBuffers);
						doc.InsertEndChild(constantBufferListNode);
						for(int i = 0; i < shaderDesc.ConstantBuffers; i++)
						{
							ID3D11ShaderReflectionConstantBuffer* constantBuffer = pReflector->GetConstantBufferByIndex(i);
							D3D11_SHADER_BUFFER_DESC constantBufferDesc;
							constantBuffer->GetDesc(&constantBufferDesc);
							tinyxml2::XMLElement *constantBufferNode = doc.NewElement("constantBuffer");
							constantBufferNode->SetAttribute("index", i);
							constantBufferNode->SetAttribute("name", constantBufferDesc.Name);
							constantBufferNode->SetAttribute("count", constantBufferDesc.Variables);
							constantBufferNode->SetAttribute("sizeInByte", constantBufferDesc.Size);
							constantBufferListNode->InsertEndChild(constantBufferNode);
							for(int j = 0; j < constantBufferDesc.Variables; j++)
							{
								ID3D11ShaderReflectionVariable* variable = constantBuffer->GetVariableByIndex(j);
								D3D11_SHADER_VARIABLE_DESC variableDesc;
								variable->GetDesc(&variableDesc);
								tinyxml2::XMLElement *variableNode = doc.NewElement("variable");
								variableNode->SetAttribute("index", j);
								variableNode->SetAttribute("name", variableDesc.Name);
								variableNode->SetAttribute("offsetInBuffer", variableDesc.StartOffset);
								variableNode->SetAttribute("sizeInByte", variableDesc.Size);
								constantBufferNode->InsertEndChild(variableNode);
							}
						}
					}
					pReflector->Release();
					doc.SaveFile(outputPath.c_str());
				}
				delete[] buffer;
			}
			//_tprintf(TEXT("  %s   %ld bytes\n"), ffd.cFileName, filesize.QuadPart);
			/*
			

			ID3D11ShaderReflection* pReflector = NULL; 
			D3DReflect( pPixelShaderBuffer->GetBufferPointer(), pPixelShaderBuffer->GetBufferSize(), 
						IID_ID3D11ShaderReflection, (void**) &pReflector);
						*/
		}
	}
	while (FindNextFileA(hFind, &ffd) != 0);
	device->Release();
}